home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / daemons / nfs / nfs-serv.2be / nfs-serv / nfs-server-2.2beta16 / realpath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-06  |  3.9 KB  |  169 lines

  1. /*
  2.  * realpath.c -- canonicalize pathname by removing symlinks
  3.  * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU Library Public License as published by
  7.  * the Free Software Foundation; either version 2, or (at your option)
  8.  * any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU Library Public License for more details.
  14.  */
  15.  
  16. #ifdef HAVE_CONFIG_H
  17. #include <config.h>
  18. #endif
  19.  
  20. #include <sys/types.h>
  21. #if defined(HAVE_UNISTD_H) || defined(STDC_HEADERS)
  22. #include <unistd.h>
  23. #endif
  24. #include <stdio.h>
  25. #ifdef HAVE_STRING_H
  26. #include <string.h>
  27. #else
  28. #include <strings.h>
  29. #endif
  30. #ifdef _POSIX_VERSION
  31. #include <limits.h>            /* for PATH_MAX */
  32. #else
  33. #include <sys/param.h>            /* for MAXPATHLEN */
  34. #endif
  35. #include <errno.h>
  36. #ifndef STDC_HEADERS
  37. extern int errno;
  38. #endif
  39.  
  40. #include <sys/stat.h>            /* for S_IFLNK */
  41.  
  42. #ifndef PATH_MAX
  43. #ifdef _POSIX_VERSION
  44. #define PATH_MAX _POSIX_PATH_MAX
  45. #else
  46. #ifdef MAXPATHLEN
  47. #define PATH_MAX MAXPATHLEN
  48. #else
  49. #define PATH_MAX 1024
  50. #endif
  51. #endif
  52. #endif
  53.  
  54. #define MAX_READLINKS 32
  55.  
  56. #ifdef __STDC__
  57. char *realpath(const char *path, char *resolved_path)
  58. #else
  59. char *realpath(path, resolved_path)
  60. const char *path;
  61. char *resolved_path;
  62. #endif
  63. {
  64.     char copy_path[PATH_MAX];
  65.     char link_path[PATH_MAX];
  66.     char *new_path = resolved_path;
  67.     char *max_path;
  68.     int readlinks = 0;
  69.     int n;
  70.  
  71.     /* Make a copy of the source path since we may need to modify it. */
  72.     strcpy(copy_path, path);
  73.     path = copy_path;
  74.     max_path = copy_path + PATH_MAX - 2;
  75.     /* If it's a relative pathname use getwd for starters. */
  76.     if (*path != '/') {
  77. #ifdef HAVE_GETCWD
  78.         getcwd(new_path, PATH_MAX - 1);
  79. #else
  80.         getwd(new_path);
  81. #endif
  82.         new_path += strlen(new_path);
  83.         if (new_path[-1] != '/')
  84.             *new_path++ = '/';
  85.     }
  86.     else {
  87.         *new_path++ = '/';
  88.         path++;
  89.     }
  90.     /* Expand each slash-separated pathname component. */
  91.     while (*path != '\0') {
  92.         /* Ignore stray "/". */
  93.         if (*path == '/') {
  94.             path++;
  95.             continue;
  96.         }
  97.         if (*path == '.') {
  98.             /* Ignore ".". */
  99.             if (path[1] == '\0' || path[1] == '/') {
  100.                 path++;
  101.                 continue;
  102.             }
  103.             if (path[1] == '.') {
  104.                 if (path[2] == '\0' || path[2] == '/') {
  105.                     path += 2;
  106.                     /* Ignore ".." at root. */
  107.                     if (new_path == resolved_path + 1)
  108.                         continue;
  109.                     /* Handle ".." by backing up. */
  110.                     while ((--new_path)[-1] != '/')
  111.                         ;
  112.                     continue;
  113.                 }
  114.             }
  115.         }
  116.         /* Safely copy the next pathname component. */
  117.         while (*path != '\0' && *path != '/') {
  118.             if (path > max_path) {
  119.                 errno = ENAMETOOLONG;
  120.                 return NULL;
  121.             }
  122.             *new_path++ = *path++;
  123.         }
  124. #ifdef S_IFLNK
  125.         /* Protect against infinite loops. */
  126.         if (readlinks++ > MAX_READLINKS) {
  127.             errno = ELOOP;
  128.             return NULL;
  129.         }
  130.         /* See if latest pathname component is a symlink. */
  131.         *new_path = '\0';
  132.         n = readlink(resolved_path, link_path, PATH_MAX - 1);
  133.         if (n < 0) {
  134.             /* EINVAL means the file exists but isn't a symlink. */
  135.             if (errno != EINVAL)
  136.                 return NULL;
  137.         }
  138.         else {
  139.             /* Note: readlink doesn't add the null byte. */
  140.             link_path[n] = '\0';
  141.             if (*link_path == '/')
  142.                 /* Start over for an absolute symlink. */
  143.                 new_path = resolved_path;
  144.             else
  145.                 /* Otherwise back up over this component. */
  146.                 while (*(--new_path) != '/')
  147.                     ;
  148.             /* Safe sex check. */
  149.             if (strlen(path) + n >= PATH_MAX) {
  150.                 errno = ENAMETOOLONG;
  151.                 return NULL;
  152.             }
  153.             /* Insert symlink contents into path. */
  154.             strcat(link_path, path);
  155.             strcpy(copy_path, link_path);
  156.             path = copy_path;
  157.         }
  158. #endif /* S_IFLNK */
  159.         *new_path++ = '/';
  160.     }
  161.     /* Delete trailing slash but don't whomp a lone slash. */
  162.     if (new_path != resolved_path + 1 && new_path[-1] == '/')
  163.         new_path--;
  164.     /* Make sure it's null terminated. */
  165.     *new_path = '\0';
  166.     return resolved_path;
  167. }
  168.  
  169.